#ifndef DBFILE_H
#define DBFILE_H

#include "Comparison.h"
#include "ComparisonEngine.h"
#include "TwoWayList.h"
#include "Record.h"
#include "File.h"
#include "Schema.h"
#include "BigQ.h"
#include <deque>

typedef enum {heap, sorted, tree} ftype;

typedef struct SERIAL{
	ftype dbType;
	int runLength;
	int numAtts;
	int whichAtts[MAX_ANDS];
	Type whichTypes[MAX_ANDS];
}Serial;

typedef struct SortOrder{
	OrderMaker *maker;
	int runLength;
} SortOrder;

class DBFile{

	class DataFile{
	protected:
		File file;
		Page *currentPg;
		unsigned int pgCount;
		int currentPgNum;

		DataFile();
		virtual ~DataFile();
		int TryAddPageAndRecord(Record &temp);
		int AttemptGetOnNextPage(Record &fetchMe);
		void CreateTopOfFile();
		char * CreateNameHeader(const char *name);
		void CreateSetup(char *name);
		int Next(Record &fetchMe);

	public:
		ftype dbType;
		int Open(char *name);
		void AddPageAndUpdatePtr();
		virtual int Add(Record &addMe) =0;
		virtual void CreateHeader(const char *name, void *startup) = 0;
		virtual void Load(Schema &mySchema, char *loadMe) = 0;
		virtual void Create(char *name, void *startup) = 0;
		virtual void MoveFirst() = 0;
		virtual int GetNext(Record &fetchMe) = 0;
		virtual int Close() = 0;
		virtual int GetNext(Record &fetchMe, CNF &applyMe, Record &literal) = 0;
	};

	class HeapFile : public DataFile{
	public:
		HeapFile();
		~HeapFile();
		int Add(Record &addMe);
		void CreateHeader(const char *name, void *startup);
		void Load(Schema &mySchema, char *loadMe);
		void Create(char *name, void *startup);
		void MoveFirst();
		int GetNext(Record &fetchMe);
		int GetNext(Record &fetchMe, CNF &applyMe, Record &literal);
		int Close();
	};
	class SortFile : public DataFile{

		BigQ *sorter;
		OrderMaker *sortOrder;
		ComparisonEngine ce;
		int runLength;
		bool writeEnabled;
		// Stuff for binary search... START
		OrderMaker *query;
		int firstPageNum;
		int firstRecordNum;
		int lastPageNum;
		int lastRecordNum;
		int currentPageNum;
		int currentRecordNum;
		bool found;
		bool fail;
		Page *searchPage;
		// Stuff for binary search... END
		char * CreateSortNameHeader(const char *name);
		char * CreateSortHeader(const char *name);
		void CommitTransaction();
		void Rollback();
	public:
		SortFile();
		~SortFile();
		int Add(Record &addMe);
		int TryAddPageAndRecord(Record *addMe);
		void ReadSorted(int buffer[]);
		bool TestAndClearWriteEnable();
		bool TestAndSetWriteEnable();
		void BigQSetup();
		void BigQShutdown();
		void BigQCleanup();
		void CreateHeader(const char *name, void *startup);
		void Load(Schema &mySchema, char *loadMe);
		void Create(char *name, void *startup);
		void MoveFirst();
		int GetNext(Record &fetchMe);
		int GetNext(Record &fetchMe, CNF &applyMe, Record &literal);
		int BinarySearch(Record *fetchMe, Record &literal, bool start);
		void BuildQuery(CNF &applyMe);
		int Close();
	};
	class TreeFile : public DataFile{
	public:
		TreeFile();
		~TreeFile();
		int Add(Record &addMe);
		void CreateHeader(const char *name, void *startup);
		void Load(Schema &mySchema, char *loadMe);
		void Create(char *name, void *startup);
		void MoveFirst();
		int GetNext(Record &fetchMe);
		int GetNext(Record &fetchMe, CNF &applyMe, Record &literal);
		int Close();
	};

 private:
 DataFile *dataFile;

 // Used to read a header file containing information regarding to the type
 // of file storage being implemented. Assumes DBFile has already been created.
 void ReadHeader(const char *name);

 void HandleError(int errorCode);

 char *CreateNameHeader(const char *name);

 public:

  DBFile();

  // Forces the pointer to correspond to the first record in the file
  void MoveFirst();

  // Used to add records to the file. For the purposes of the heap file
  // That we are implementing, this function simply appends the new
  // Record to the end of the file.
  void Add(Record &addMe);

  // Gets the next record from the file and returns it to the user, where
  // next is defined to be relative to the current pointer location.
  // Pointer is then incremented to the next file. Returns a 0 if no more
  // valid records returned from the call  ( so if last record already
  // returned, then return a 0 if there is a call).
  int GetNext(Record &fetchMe);

  // This version also accepts a selection predicate (CNF expression)
  // The literal record is used to check the selection predicate, and is 
  // created when the parse tree for the CNF is processed
  int GetNext(Record &fetchMe, CNF &applyMe, Record &literal);
  
  // This function actually creates the file. Takes in a text string telling
  // the db where to store the binary data (use the File class from File.h 
  // in storing the file). The second param tells us the type of file. The final 
  // currently a dummy var to be used in the future.
  int Create(char *name, ftype myType, void *startup);

  // Assumes the DBFile already exists and has been created and closed. 
  // Only thing passed is the physical location of the file.
  int Open(char *name);

  // Closes the file. Return 0 on fail and 1 on success
  int Close();

  // bulk loads the DBFile instance from a text file, appending new data to it w/
  // Record::SuckNextRecord. The *char loadME is the name of the file to bulk load.
  void Load(Schema &mySchema, char *loadMe);
  
};

#endif
